<template>
  <a-table
    :columns="dynamicColumns"
    :loading="loading"
    :row-selection="rowSelection"
    :row-key="rowKey"
    size="middle"
    :data-source="data"
    :pagination="pageOptions"
    bordered
    :custom-row="customRow"
    v-bind="{ ...$props, ...$attrs }"
    class="wrap"
    @change="paginationChange"
  >
    <!--  自定义slots start-->
    <template v-for="(value, key) in $slots" #[key]="slotProps">
      <slot :name="key" v-bind="slotProps"></slot>
    </template>
    <!--    自定义slots end-->

    <!--    是否有自定义显示slots start-->
    <template
      v-for="slotItem in dynamicColumns.filter((item) => item.slots)"
      :key="slotItem.dataIndex || slotItem.slots?.customRender"
      #[slotItem.slots?.customRender]="slotProps"
    >
      <!--        自定义渲染start-->
      <slot
        v-if="$slots[slotItem.slots?.customRender]"
        :name="slotItem.slots?.customRender"
        v-bind="slotProps"
      ></slot>
      <!--        自定义渲染end-->

      <!--     非自定义渲染start -->
      <template v-else>
        <!--        非操作 start-->
        <template v-if="slotItem.slots?.customRender !== 'action'">
          <!--        使用自定义组件格式化显示start-->
          <template v-if="slotItem.slotsType === 'component'">
            <component :is="slotItem.slotsFunc && slotItem.slotsFunc(slotProps.record)" />
          </template>
          <!--        使用自定义组件格式化显示end-->
          <!--        使用自定义函数格式化显示-->
          <template v-if="slotItem.slotsType === 'format'">
            {{
              slotItem.slotsFunc &&
              slotItem.slotsFunc(
                slotProps.record[slotItem.dataIndex || slotItem.key],
                slotProps.record
              )
            }}
          </template>
          <!--        链接用于跳转-->
          <template v-if="slotItem.slotsType === 'link'">
            <router-link :to="slotItem.linkPath + slotProps.record[slotItem.linkId]">{{
              slotProps.text
            }}</router-link>
          </template>
        </template>
        <!--      非操作 end-->

        <!--        操作start-->
        <div
          v-if="slotItem.slots?.customRender === 'action'"
          :key="slotItem.slots?.customRender"
          class="actions"
        >
          <!--        对表格的操作动作start-->
          <template v-for="(action, index) in actions">
            <template v-if="action.type === 'select'">
              <!--              下拉选择器-->
              <a-select :key="index" v-model:value="slotProps.record[action.key]" size="small">
                <Option v-for="option in action.options" :key="option.value" :value="option.value">
                  {{ option.label }}
                </Option>
              </a-select>
            </template>
            <!--            文本按钮-->
            <template v-if="action.type === 'text'">
              <template v-if="action.text === '恢复' && !slotProps.record.resumable">
                <a-button :key="index" type="link" disabled>{{ action.text }}</a-button>
              </template>
              <template v-else>
                <template v-if="action.text === '下载'">
                  <a
                    :key="index"
                    :href="slotProps.record.url"
                    :style="{ ...action.style }"
                    :class="['action-divider-vertical']"
                    @click="actionEvent(slotProps.record, action.func)"
                  >
                    {{ action.text }}
                  </a>
                </template>
                <template v-else>
                  <span
                    :key="index"
                    :style="{ ...action.style }"
                    :class="['action-divider-vertical']"
                    @click="actionEvent(slotProps.record, action.func)"
                  >
                    {{ action.text }}
                  </span>
                </template>
              </template>
            </template>
            <!--            删除按钮 气泡确认框-->
            <template v-if="action.type === 'popconfirm'">
              <a-popconfirm
                :key="index"
                placement="leftTop"
                @confirm="actionEvent(slotProps.record, action.func, 'del')"
              >
                <template #title> 您确定要删除吗？ </template>
                <span
                  :key="index"
                  :style="{ ...action.style }"
                  :class="['action-divider-vertical']"
                >
                  {{ action.text }}
                </span>
              </a-popconfirm>
            </template>
          </template>
          <!--        对表格的操作动作end-->
        </div>
        <!--      操作end-->
      </template>
      <!--      非自定义渲染end-->
    </template>
    <!--    是否有自定义显示slots end-->
  </a-table>
</template>

<script lang="ts">
  import { defineComponent, reactive, PropType, toRefs } from 'vue'
  import { Card, Select, Table, Popconfirm, Button } from 'ant-design-vue'
  import { TableProps } from 'ant-design-vue/lib/table/interface'
  import { usePagination, PageOption } from '@/hooks/usePagination'
  import { useDragRow, useDragCol } from './hooks'
  import { Column } from './types'
  import { useRouter } from 'vue-router'

  export default defineComponent({
    name: 'DynamicTable',
    components: {
      [Table.name]: Table,
      [Card.name]: Card,
      [Button.name]: Button,
      [Select.name]: Select,
      [Popconfirm.name]: Popconfirm,
      Option: Select.Option
    },
    inheritAttrs: false,
    props: {
      dynamicColumns: {
        type: Object as PropType<Column[]>,
        required: true
      },
      getListFunc: {
        // 获取列表数据函数API
        type: Function,
        required: true
      },
      rowSelection: {
        type: Object
      },
      rowKey: {
        // 表格唯一字段
        type: [String, Function] as PropType<string | ((record: any) => string)>
      },
      pageOption: {
        // 分页参数
        type: Object as PropType<PageOption>,
        default: () => ({})
      },
      dragColEnable: {
        type: Boolean as PropType<boolean>,
        default: true
      },
      dragRowEnable: Boolean as PropType<boolean>
    },
    emits: ['change'],
    setup(props, { emit }) {
      const { pageOptions } = usePagination()

      Object.assign(pageOptions.value, props.pageOption)

      // 开启表格伸缩列
      props.dragColEnable && useDragCol(props.dynamicColumns)

      const state = reactive({
        expandItemRefs: {},
        customRow: () => ({} as TableProps['customRow']),
        data: [], // 表格数据
        actions:
          props.dynamicColumns.find((item) => (item.dataIndex || item.key) == 'action')?.actions ||
          [], // 表格操作（如：编辑、删除的按钮等）
        loading: false // 表格加载
      })

      // 获取表格数据
      const refreshTableData = async (params = {}) => {
        params = {
          pageNumber: pageOptions.value.current,
          pageSize: pageOptions.value.pageSize,
          ...props.pageOption,
          ...params
        }
        state.loading = true
        const { data, pageNumber, pageSize, total } = await props
          .getListFunc(params)
          .finally(() => {
            state.loading = false
          })
        Object.assign(pageOptions.value, {
          current: ~~pageNumber,
          pageSize: ~~pageSize,
          total: ~~total
        })
        state.data = data
        // 是否可以拖拽行
        props.dragRowEnable && (state.customRow = useDragRow<any>(state.data)!)
      }

      refreshTableData()
      const router = useRouter()

      // 操作事件
      const actionEvent = async (record, func, actionType = '') => {
        // 将refreshTableData放入宏任务中,等待当前微任务拿到结果进行判断操作，再请求表格数据
        await func({ record, router, props }, () => setTimeout(() => refreshTableData()))
        // 如果为删除操作,并且删除成功，当前的表格数据条数小于2条,则当前页数减一,即请求前一页
        if (actionType == 'del' && state.data.length < 2) {
          pageOptions.value.current = Math.max(1, pageOptions.value.current - 1)
        }
      }

      // 分页改变
      const paginationChange = (pagination, filters, sorter, { currentDataSource }) => {
        const { field, order } = sorter
        console.log(pagination)
        pageOptions.value = {
          ...pageOptions.value,
          ...pagination
        }
        refreshTableData({
          pageSize: pagination.pageSize,
          pageNumber: pagination.current,
          ...props.pageOption,
          ...filters,
          field,
          order
        })
        emit('change', pagination, filters, sorter, { currentDataSource })
      }

      // dataIndex 可以为 a.b.c
      // const getDataIndexVal = (dataIndex, record) => dataIndex.split('.').reduce((pre, curr) => pre[curr], record)

      const buttonProps = {
        size: 'small'
      }

      return {
        ...toRefs(state),
        pageOptions,
        buttonProps,
        actionEvent,
        refreshTableData,
        paginationChange,
        emit,
        router
      }
    }
  })
</script>

<style lang="scss" scoped>
  ::v-deep(.ant-table .ant-table-title) {
    display: flex;
  }

  .ant-btn {
    padding: 0;
    margin: 0;
  }

  .actions > * {
    margin-right: 10px;
  }

  .action-divider-vertical {
    padding-right: 5px;
    border-right-color: #d9d9d9;
    border-right-style: solid;
    border-right-width: 1px;

    &:last-child {
      border-right: 0 solid #fff;
    }
  }
</style>
